package edu.tongji.structureplayer.ui
{
    import flash.events.Event;
    import flash.events.MouseEvent;
    
    import mx.containers.Panel;
    import mx.controls.Button;
    import mx.effects.Resize;
    import mx.events.EffectEvent;
    import mx.managers.CursorManager;
    import mx.managers.CursorManagerPriority;
    
    
    public class StructurePanel extends Panel
    {
        private var resize:Resize;
        private var effectTime: Number = 400;
        private var resizeMargin:Number = 7;
        
        private var prevHeight:Number;
        private var prevWidth:Number;
        private var prevX:Number;
        private var prevY:Number;
        private var prevPanelX:Number;
        private var prevPanelY:Number;
        
        private var onBottomRightResize:Boolean = false;
        private var onTopRightResize:Boolean = false;
        private var onBottomLeftResize:Boolean = false;
        private var onTopLeftResize:Boolean = false;
        private var onRightResize:Boolean = false;
        private var onLeftResize:Boolean = false;
        private var onTopResize:Boolean = false;
        private var onBottomResize:Boolean = false;
        
        private var maxBtn:Button;
        private var minBtn: Button;
        private var closeBtn: Button;
        
        private var _defaultCursorName:String;
        private var defaultCursor:Class;
        
        public static var RESIZE_BOTTOM_RIGHT:String = "resizeBottomRight";
        
        private static var MOUSE_CURSOR:String = "mouseCursor";
        private static var CROSSHAIR_CURSOR:String = "crosshairCursor";
        private static var SIDE_LEFT_CURSOR:String = "sideLeftCursor";
        private static var SIDE_RIGHT_CURSOR:String = "sideRightCursor";
        private static var SIDE_TOP_CURSOR:String = "sideTopCursor";
        private static var SIDE_BOTTOM_CURSOR:String = "sideBottomCursor";
        private static var CORNER_BOTTOM_RIGHT_CURSOR:String = "cornerBottomRightCursor";
        private static var CORNER_BOTTOM_LEFT_CURSOR:String = "cornerBottomLeftCursor";
        private static var CORNER_TOP_RIGHT_CURSOR:String = "cornerTopRightCursor";
        private static var CORNER_TOP_LEFT_CURSOR:String = "cornerTopLeftCursor";
        
        public function StructurePanel()
        {
            super();
            this.minWidth = 200;
            this.minHeight = 100;
            this.maxWidth = 1280;
            this.maxHeight = 1024;
        }
        
        public function get defaultCursorName():String
        {
            return _defaultCursorName;
        }

        public function set defaultCursorName(value:String):void
        {
            _defaultCursorName = value;
        }

        public override function initialize():void
        {
            super.initialize();
            initEffect();
            initEvent();
            initCursor();
        }
        
        public override function setVisible(value:Boolean, noEvent:Boolean=false):void
        {
            super.setVisible(value, noEvent);
            if (value)
                this.setActive();
        }
        
        protected override function createChildren():void
        {
            super.createChildren();
            
            
            minBtn = new Button();
            minBtn.addEventListener("click", doMin);
            minBtn.setStyle("downIcon",Assets.minDownIcon);
            minBtn.setStyle("upIcon",Assets.minUpIcon);
            minBtn.setStyle("overIcon", Assets.minOverIcon);
            minBtn.visible = true;
            this.rawChildren.addChild(minBtn);
            
            maxBtn = new Button();
            maxBtn.addEventListener("click", doMax);
            maxBtn.setStyle("downIcon",Assets.maxDownIcon);
            maxBtn.setStyle("upIcon",Assets.maxUpIcon);
            maxBtn.setStyle("overIcon", Assets.maxOverIcon);
            maxBtn.visible = true;
            this.rawChildren.addChild(maxBtn);
            
            closeBtn = new Button();
            closeBtn.addEventListener("click", doClose);
            closeBtn.setStyle("downIcon",Assets.closeDownIcon);
            closeBtn.setStyle("upIcon",Assets.closeUpIcon);
            closeBtn.setStyle("overIcon", Assets.closeOverIcon);
            closeBtn.visible = true;
            this.rawChildren.addChild(closeBtn);
        }
        
        protected override function layoutChrome(unscaledWidth:Number, unscaledHeight:Number):void
        {
            super.layoutChrome(unscaledWidth, unscaledHeight);
            
            var margin:int = 4;
            var pixelsFromRight:int = 12;
            var pixelsFromTop:int = 8;
            var buttonWidth:int = 16;
            
            var x:int = this.width - pixelsFromRight - buttonWidth/2;
            var y:int = pixelsFromTop + buttonWidth/2;
            closeBtn.move(x, y);
            
            x -= (buttonWidth + margin);
            maxBtn.move(x, y);
            
            x -= (buttonWidth + margin);
            minBtn.move(x, y);
        }
        
        private function doDrag(event:Event):void
        {
            this.startDrag();
        }
        
        private function doDrop(event:Event):void
        {
            this.stopDrag();
        }
        
        private function doMin(event:Event):void
        {
            if (isMinimized())
                return;
            prevHeight = this.height;
            prevWidth = this.width;
            minEffect();
        }
        
        private function doMax(event:Event):void
        {
            if (isMaximized())
                return;
            var tempHeight:Number = this.height;
            var tempWidth:Number = this.width;
            maxEffect();
            prevHeight = tempHeight;
            prevWidth = tempWidth;
        }
        
        private function doClose(event:Event):void
        {
            this.setVisible(false);
        }
        
        private function doMouseDown(event:MouseEvent):void
        {
            this.setActive();
            if (isCornerBottomRight())
                onBottomRightResize = true;
            else if (isCornerBottomLeft())
                onBottomLeftResize = true;
            else if (isCornerTopRight())
                onTopRightResize = true;
            else if (isCornerTopLeft())
                onTopLeftResize = true;
            else if (isSideLeft())
                onLeftResize = true;
            else if (isSideRight())
                onRightResize = true;
            else if (isSideTop())
                onTopResize = true;
            else if (isSideBottom())
                onBottomResize = true;
            else if (isOnTitleBar())
            {
                this.startDrag();
                return;
            }
            else 
                return;
            
            prevX = event.stageX;
            prevY = event.stageY;
            prevPanelX = this.x;
            prevPanelY = this.y;
            prevWidth = this.width;
            prevHeight = this.height;
        }
        
        private function doMouseUp(event:MouseEvent):void
        {
            if (isCornerBottomRight())
                onBottomRightResize = false;
            else if (isCornerBottomLeft())
                onBottomLeftResize = false;
            else if (isCornerTopRight())
                onTopRightResize = false;
            else if (isCornerTopLeft())
                onTopLeftResize = false;
            else if (isSideLeft())
                onLeftResize = false;
            else if (isSideRight())
                onRightResize = false;
            else if (isSideTop())
                onTopResize = false;
            else if (isSideBottom())
                onBottomResize = false;
            else if (isOnTitleBar())
                this.stopDrag();
            else {}
            
        }
        
        private function doMouseMove(event:MouseEvent):void
        {
            event.stopImmediatePropagation();
            //trace ("debug:" + event.stageX + ":" + event.stageY);
            
            
            // Out of control of this panel.
            if (isOutOfControl() && !isOnResizing())
            {
                switchCursor(MOUSE_CURSOR);
                return;
            }
            
            // Change cursor when the cursor is in the resizing area.
            if (isCornerBottomRight())
                switchCursor(CORNER_BOTTOM_RIGHT_CURSOR);
            else if (isCornerBottomLeft())
                switchCursor(CORNER_BOTTOM_LEFT_CURSOR);
            else if (isCornerTopRight())
                switchCursor(CORNER_TOP_RIGHT_CURSOR);
            else if (isCornerTopLeft())
                switchCursor(CORNER_TOP_LEFT_CURSOR);
            else if (isSideLeft())
                switchCursor(SIDE_LEFT_CURSOR);
            else if (isSideRight())
                switchCursor(SIDE_RIGHT_CURSOR);
            else if (isSideTop())
                switchCursor(SIDE_TOP_CURSOR);
            else if (isSideBottom())
                switchCursor(SIDE_BOTTOM_CURSOR);
            else if (isOnTitleBar())
                switchCursor(MOUSE_CURSOR);
            else 
                switchCursor(_defaultCursorName);
            
            var xGap:Number = event.stageX - prevX;
            var yGap:Number = event.stageY - prevY;
            // Resize panel by adjusting its width and height.
            if (onBottomRightResize)
            {
                switchCursor(CORNER_BOTTOM_RIGHT_CURSOR);
                toBottom(yGap);
                toRight(xGap);
            }
            else if (onBottomLeftResize)
            {
                switchCursor(CORNER_BOTTOM_LEFT_CURSOR);
                toBottom(yGap);
                toLeft(xGap);
            }
            else if (onTopRightResize)
            {
                switchCursor(CORNER_TOP_RIGHT_CURSOR);
                toTop(yGap);
                toRight(xGap);
            }
            else if (onTopLeftResize)
            {
                switchCursor(CORNER_TOP_LEFT_CURSOR);
                toTop(yGap);
                toLeft(xGap);
            }
            else if (onLeftResize)
            {
                switchCursor(SIDE_LEFT_CURSOR);
                toLeft(xGap);
                //trace (x + "," + width + "," + prevX + "," + event.stageX);
            }
            else if (onRightResize)
            {
                switchCursor(SIDE_RIGHT_CURSOR);
                toRight(xGap);
            }
            else if (onTopResize)
            {
                switchCursor(SIDE_TOP_CURSOR);
                toTop(yGap);
            }
            else if (onBottomResize)
            {
                switchCursor(SIDE_BOTTOM_CURSOR);
                toBottom(yGap);
            }
            else {}
            
            if (isInvalidSize())
            {
                this.width = prevWidth;
                this.height = prevHeight;
                this.x = prevPanelX;
                this.y = prevPanelY;
                makeOnResizingFalse();
            }
        }
        
        private function toLeft(xGap:Number):void
        {
            this.move(prevPanelX + xGap, this.y);
            this.width = prevWidth - xGap;
        }
        
        private function toRight(xGap:Number):void
        {
            this.width = prevWidth + xGap;
        }
        
        private function toTop(yGap:Number):void
        {
            this.move(this.x, prevPanelY + yGap);
            this.height = prevHeight - yGap;
        }
        
        private function toBottom(yGap:Number):void
        {
            this.height = prevHeight + yGap;
        }
        
        private function makeOnResizingFalse():void
        {
            onRightResize =false;
            onLeftResize =false;
            onTopResize =false;
            onBottomResize =false;
            onBottomRightResize =false;
            onBottomLeftResize =false;
            onTopLeftResize =false;
            onTopRightResize =false;
        }
        
        /*private function resizeOnLeft():void
        {
            var delta:Number = gapToLeft - this.mouseX;
            this.move(this.x - delta, this.y);
            this.width += delta;
        }*/
        /*
        private function doMouseOverTitleBar(event:MouseEvent):void
        {
            if (isNearToTop(this.mouseX, this.mouseY))
                switchCursor("sideTopCursor");
            else
                switchCursor("mouseCursor");
        }*/
        
        private function doMouseOut(event:Event):void
        {
            if (onBottomRightResize)
                switchCursor(CORNER_BOTTOM_RIGHT_CURSOR);
            else if (onBottomLeftResize)
                switchCursor(CORNER_BOTTOM_LEFT_CURSOR);
            else if (onTopRightResize)
                switchCursor(CORNER_TOP_RIGHT_CURSOR);
            else if (onTopLeftResize)
                switchCursor(CORNER_TOP_LEFT_CURSOR);
            else if (onLeftResize)
                switchCursor(SIDE_LEFT_CURSOR);
            else if (onRightResize)
                switchCursor(SIDE_RIGHT_CURSOR);
            else if (onTopResize)
                switchCursor(SIDE_TOP_CURSOR);
            else if (onBottomResize)
                switchCursor(SIDE_BOTTOM_CURSOR);
            else
                switchCursor(MOUSE_CURSOR);
        }
        
        private function doEffectStart(event:EffectEvent):void
        {
            this.removeEventListener(MouseEvent.MOUSE_MOVE, doMouseMove);
        }
        
        private function doEffectEnd(event:EffectEvent):void
        {
            this.addEventListener(MouseEvent.MOUSE_MOVE, doMouseMove);
        }
        
        private function isOutOfControl():Boolean
        {
            return this.mouseX<0 || this.mouseY<0 || 
                this.mouseX>this.width || this.mouseY>this.height;
        }
        
        public function isOnResizing():Boolean
        {
            return onRightResize || onLeftResize || onTopResize ||
                onBottomResize || onBottomRightResize || onBottomLeftResize ||
                onTopLeftResize || onTopRightResize;
        }
        
        private function isInvalidSize():Boolean
        {
            if (isMinimized())
                return false;
            return this.width>this.maxWidth||this.width<this.minWidth||
                this.height>this.maxHeight||this.height<this.minHeight;
        }
        
        private function isCornerBottomRight():Boolean
        {
            if (isMinimized())
                return false;
            return this.width-resizeMargin<=this.mouseX && this.mouseX<=this.width 
                && this.height-resizeMargin<=this.mouseY && this.mouseY<=this.height;
        }
        
        private function isCornerBottomLeft():Boolean
        {
            if (isMinimized())
                return false;
            return 0<=this.mouseX && this.mouseX<=resizeMargin 
                && this.height-resizeMargin<=this.mouseY && this.mouseY<=this.height;
        }
        
        private function isCornerTopRight():Boolean
        {
            if (isMinimized())
                return false;
            return this.width-resizeMargin<=this.mouseX && this.mouseX<=this.width 
                && 0<=this.mouseY && this.mouseY<=resizeMargin;
        }
        
        private function isCornerTopLeft():Boolean
        {
            if (isMinimized())
                return false;
            return 0<=this.mouseX && this.mouseX<=resizeMargin 
                && 0<=this.mouseY && this.mouseY<=resizeMargin;
        }
        
        private function isSideLeft():Boolean
        {
            if (isMinimized())
                return false;
            return 0<=this.mouseX && this.mouseX<=resizeMargin;
        }
        
        private function isSideRight():Boolean
        {
            if (isMinimized())
                return false;
            return this.width-resizeMargin<=this.mouseX 
                && this.mouseX<=this.width;
        }
        
        private function isSideTop():Boolean
        {
            if (isMinimized())
                return false;
            return 0<=this.mouseY && this.mouseY<=resizeMargin;
        }
        
        private function isSideBottom():Boolean
        {
            if (isMinimized())
                return false;
            return this.height-resizeMargin<=this.mouseY 
                && this.mouseY<=this.height;
        }
        
        private function isOnTitleBar():Boolean
        {
            return 0<=this.mouseX && this.mouseX<=this.width 
                && 0<=this.mouseY && this.mouseY<=this.titleBar.height;
        }
        
        private function switchCursor(cursorName:String):void
        {
            CursorManager.removeAllCursors();
            switch (cursorName)
            {
                case CROSSHAIR_CURSOR:
                    CursorManager.setCursor(Assets.crosshairCursor, 
                        CursorManagerPriority.HIGH, -10, -10);
                    break;
                case SIDE_LEFT_CURSOR:
                    CursorManager.setCursor(Assets.sideLeftCursor,
                        CursorManagerPriority.HIGH, -10, 0);
                    break;
                case SIDE_RIGHT_CURSOR:
                    CursorManager.setCursor(Assets.sideRightCursor,
                        CursorManagerPriority.HIGH, -10, 0);
                    break;
                case SIDE_TOP_CURSOR:
                    CursorManager.setCursor(Assets.sideTopCursor,
                        CursorManagerPriority.HIGH, 0, -10);
                    break;
                case SIDE_BOTTOM_CURSOR:
                    CursorManager.setCursor(Assets.sideBottomCursor,
                        CursorManagerPriority.HIGH, 0, -10);
                    break;
                case CORNER_BOTTOM_RIGHT_CURSOR:
                    CursorManager.setCursor(Assets.cornerBottomRightCursor,
                        CursorManagerPriority.HIGH, -10, -10);
                    break;
                case CORNER_BOTTOM_LEFT_CURSOR:
                    CursorManager.setCursor(Assets.cornerBottomLeftCursor,
                        CursorManagerPriority.HIGH, -10, -10);
                    break;
                case CORNER_TOP_RIGHT_CURSOR:
                    CursorManager.setCursor(Assets.cornerTopRightCursor,
                        CursorManagerPriority.HIGH, -10, -10);
                    break;
                case CORNER_TOP_LEFT_CURSOR:
                    CursorManager.setCursor(Assets.cornerTopLeftCursor,
                        CursorManagerPriority.HIGH, -10, -10);
                    break;
                default:
                    CursorManager.setCursor(Assets.mouseCursor, 
                        CursorManagerPriority.HIGH, -4, -2);
            }
        }
        
        private function setActive():void
        {
            this.parent.setChildIndex(this, this.parent.numChildren-1);
        }
        
        private function initEffect():void
        {
            resize = new Resize(this);
            resize.heightTo = this.titleBar.height;
            resize.duration = effectTime;
        }
        
        private function initCursor():void
        {
            if (_defaultCursorName == null || 
            _defaultCursorName == MOUSE_CURSOR)
                defaultCursor = Assets.mouseCursor;
            else if (_defaultCursorName == "crosshairCursor")
                defaultCursor = Assets.crosshairCursor;
            else
                defaultCursor = Assets.mouseCursor;
        }
        
        private function initEvent():void
        {
            this.addEventListener(MouseEvent.MOUSE_DOWN, doMouseDown);
            this.addEventListener(MouseEvent.MOUSE_UP, doMouseUp);
            this.addEventListener(MouseEvent.MOUSE_MOVE, doMouseMove);
            this.addEventListener(MouseEvent.MOUSE_OUT, doMouseOut);
            this.addEventListener(EffectEvent.EFFECT_END, doEffectEnd);
            this.addEventListener(EffectEvent.EFFECT_START, doEffectStart);
        }
        
        private function minEffect():void
        {
            resize.heightTo = this.titleBar.height;
            resize.end();
            resize.play();
        }
        
        private function maxEffect():void
        {
            resize.heightTo = this.prevHeight;
            resize.end();
            resize.play();
        }
        
        public function isMinimized():Boolean
        {
            return this.height == this.titleBar.height;
        }
        
        public function isMaximized():Boolean
        {
            return ! isMinimized();
        }
    }
}